#ifndef _JPVEC3_H_
#define _JPVEC3_H_

class JPVec3
{

public:

	float x, y, z; // 3D vector coordinates

	JPVec3 (float newX=0.0f, float newY=0.0f, float newZ=0.0f) : x(newX), y(newY), z(newZ) {}

	//----------------------------------------
	// public api
	//----------------------------------------
	/*
	 * returns the dot product between this and v
	 */
	float dot(const JPVec3 &v) const;

	/*
	 * returns the cross product between this and v
	 */
	JPVec3 cross(const JPVec3 &v) const;

	/*
	 * returns the length of the vector
	 */
	float magnitude() const;

	/*
	 * returns the sqr length ofthis vector
	 */
	float sqrMagnitude() const;

	/*
	 * Normalises this vector to have length 1
	 */
	void normalise();

	/*
	 * returns a normalised version of this vector
	 */
	JPVec3 getNormalised() const;

	//----------------------------------------
	// operator overloads
	//----------------------------------------
	// = operator
	JPVec3 operator =(const JPVec3 &v)
	{
		x = v.x; y = v.y; z = v.z;
		return *this;
	}
	// + operator
	JPVec3 operator +(const JPVec3 &v) const	{ return JPVec3(v.x+x, v.y+y, v.z+z); }
	// - operator
	JPVec3 operator -(const JPVec3 &v) const	{ return JPVec3(x-v.x, y-v.y, z-v.z); }
	// * operator
	JPVec3 operator *(float n) const			{ return JPVec3(x*n, y*n, z*n); }
	// * vector operator
	JPVec3 operator *(const JPVec3 &v) const	{ return JPVec3(x*v.x, y*v.y, z*v.z);}
	// / operator
	JPVec3 operator /(float n) const			{ return JPVec3(x/n, y/n, z/n); }
	// / vector operator
	JPVec3 operator /(const JPVec3 &v) const	{ return JPVec3(x/v.x, y/v.y, z/v.z); }
	// - operator
	JPVec3 operator -() const					{ return JPVec3(-x,-y,-z); }
	// += operator
	JPVec3& operator +=(const JPVec3 &v)
	{
		x+=v.x; y+=v.y; z+=v.z;
		return *this;
	}
	// -= operator
	JPVec3& operator -=(const JPVec3 &v)
	{
		x-=v.x; y-=v.y; z-=v.z;
		return *this;
	}
	// *= operator
	JPVec3& operator *=(float n)
	{
		x*=n; y*=n; z*=n;
		return *this;
	}
	// *= vector operator
	JPVec3& operator *=(const JPVec3 &v)
	{
		x*=v.x; y*=v.y; z*=v.z;
		return *this;
	}
	// /= operator
	JPVec3& operator /=(float n)
	{
		x/=n; y/=n; z/=n;
		return *this;
	}
	// /= vector operator
	JPVec3& operator /=(const JPVec3 &v)
	{
		x/=v.x; y/=v.y; z/=v.z;
		return *this;
	}
	// [] operator
	float& operator [](int i)
	{
		// TODO: assert if i < 0 || i >2
		if(i<0||i>2) i = 0;

		return *(&x+i);
	}

	// const [] operator
	const float& operator [](int i) const
	{
		// TODO: assert if i < 0 || i >2
		if(i<0||i>2) i = 0;

		return *(&x+i);
	}

	//----------------------------------------
	// statics 
	//----------------------------------------

	/*
	 * unit vectors along each axis
	 */
	static const JPVec3 vecX;
	static const JPVec3 vecY;
	static const JPVec3 vecZ;
};


#endif // _JPVEC3_H_